package cn.com.ursaminor.mysql4j.core;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.log4j.Logger;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.RowMapper;

import cn.com.ursaminor.mysql4j.callback.KeyCallback;
import cn.com.ursaminor.mysql4j.callback.KeyValueCallback;
import cn.com.ursaminor.mysql4j.util.Const;
import cn.com.ursaminor.mysql4j.util.Mysql4jUtil;

/*
	SELECT
	    [ALL | DISTINCT | DISTINCTROW ]
	    [HIGH_PRIORITY]
	    [STRAIGHT_JOIN]
	    [SQL_SMALL_RESULT] [SQL_BIG_RESULT] [SQL_BUFFER_RESULT]
	    [SQL_NO_CACHE] [SQL_CALC_FOUND_ROWS]
	    select_expr [, select_expr] ...
	    [into_option]
	    [FROM table_references
	      [PARTITION partition_list]]
	    [WHERE where_condition]
	    [GROUP BY {col_name | expr | position}, ... [WITH ROLLUP]]
	    [HAVING where_condition]
	    [WINDOW window_name AS (window_spec)
	        [, window_name AS (window_spec)] ...]
	    [ORDER BY {col_name | expr | position}
	      [ASC | DESC], ... [WITH ROLLUP]]
	    [LIMIT {[offset,] row_count | row_count OFFSET offset}]
	    [into_option]
	    [FOR {UPDATE | SHARE}
	        [OF tbl_name [, tbl_name] ...]
	        [NOWAIT | SKIP LOCKED] 
	      | LOCK IN SHARE MODE]
	    [into_option]
	
	into_option: {
	    INTO OUTFILE 'file_name'
	        [CHARACTER SET charset_name]
	        export_options
	  | INTO DUMPFILE 'file_name'
	  | INTO var_name [, var_name] ...
	}
 */
/**
 * 该类拼接生成select语句，获取数据并转换成适当的结果。也可以仅仅作为子查询，
 * 嵌入到Query、Inserter、Updater和Deleter对象中.
 * 
 * @author 小熊
 * @version 1.0
 */
public class Query extends AbstTable
{
	private final static Logger logger = Logger.getLogger(Query.class);
	
	// --------------------------------------------------------------------------------
	
	private Table table;
	
	private StringBuffer select;
	private StringBuffer from;
	private StringBuffer where;
	private StringBuffer group;
	private StringBuffer having;
	private StringBuffer order;
	private StringBuffer limit;
	
	private BoolExpr expr;
	
	// --------------------------------------------------------------------------------
	
	/**
	 *	构造方法.
	 */
	public Query()
	{
		super();
		if(this.getClass()!=Query.class)
		{
			this.initCustomCols();
		}
	}
	
	// 初始化方法，仅在继承Query的子类中调用
	private void initCustomCols()
	{
		Field[] fs = getClass().getDeclaredFields();
		for(Field f : fs)
		{
			try
			{
				String modifier = Modifier.toString(f.getModifiers());
				if(!modifier.contains("public")) continue;
				
				if(Column.class.isAssignableFrom(f.getType()))
				{
					f.setAccessible(true);
					Column c = (Column)f.get(this);
					if(c==null)
					{
						c = (Column)f.getType().newInstance();
						f.set(this, c);
					}
					c.name = f.getName();
					c.table = this;
				}
			}
			catch(Exception e)
			{
				System.out.println(e);
			}
		}
	}
	
	// 全称
	public String getString()
	{
		return "("+getSql()+") "+getAlias();
	}
	
	/**
	 *	拼接from子句.
	 *
	 *  <p>
	 *      该方法方法拼接sql查询语句中的from子句，abstTable参数可以为配置类（Table的子类），
	 *      也可为子查询（Query）。方法可在sql语句提交之前多次调用，顺序不限，这将把多个表连接到from关键字之后。
	 *      该方法不负责表之间的关联限定，仅仅把表或者子查询放到from关键字之后，并用逗号隔开。
	 *  </p>
	 *
	 *	@param abstTable 配置类（Table的子类）或者子查询（Query）
	 *  @return 当前Query对象
	 */
	public Query from(AbstTable abstTable)
	{
		if(this.table==null && abstTable instanceof Table)
		{
			this.table = (Table)abstTable;
			this.setJdbcTemplate(abstTable.getJdbcTemplate());
		}
		
		if(from==null) from = new StringBuffer(" from ");
		else from.append(",");
		
		from.append(abstTable.getString());
		
		return this;
	}
	
	/**
	 *	拼接from子句，该方法在关联多个表时使用，可以直接设置关联表达式.
	 *
	 *  <p>
	 *      该方法方法拼接sql查询语句中的from子句，abstTable参数可以为配置类（Table的子类），
	 *      也可为子查询（Query），expr参数为多表关联的表达式，如 a.id=b.id。方法可在sql语句
	 *      提交之前多次调用，顺序不限，这将把多个表连接到from关键字之后，表达式将被放置到where子句中。
	 *  </p>
	 *  
	 *	@param abstTable 配置类（Table的子类）或者子查询（Query）
	 *	@param expr 关联表达式
	 *  @return 当前Query对象
	 */
	public Query from(AbstTable abstTable, BoolExpr expr)
	{
		from(abstTable);
		where(expr);
		return this;
	}
	
	/**
	 *	拼接left join … on子句.
	 *
	 *  <p>
	 *      该方法方法拼接sql查询语句中的left join … on子句，abstTable参数可以为配置类（Table的子类），
	 *      也可为子查询（Query），on参数为多表关联的表达式，如 a.id=b.id。
	 *  </p>
	 *
	 *	@param abstTable 配置类（Table的子类）或者子查询（Query）
	 *  @param on 关联表达式
	 *  @return 当前Query对象
	 */
	public Query leftJoin(AbstTable abstTable, BoolExpr on)
	{
		from.append(Const.LEFT_JOIN).append(abstTable.getString()).append(Const.ON).append(on.getString());
		return this;
	}
	
	/**
	 *	拼接right join … on子句.
	 *
	 *  <p>
	 *      该方法方法拼接sql查询语句中的right join … on子句，abstTable参数可以为配置类（Table的子类），
	 *      也可为子查询（Query），on参数为多表关联的表达式，如 a.id=b.id。
	 *  </p>
	 *
	 *	@param abstTable 配置类（Table的子类）或者子查询（Query）
	 *  @param on 关联表达式
	 *  @return 当前Query对象
	 */
	public Query rightJoin(AbstTable abstTable, BoolExpr on)
	{
		from.append(Const.RIGHT_JOIN).append(abstTable.getString()).append(Const.ON).append(on.getString());
		return this;
	}
	
	/**
	 *	拼接inner join … on子句.
	 *
	 *  <p>
	 *      该方法方法拼接sql查询语句中的inner join … on子句，abstTable参数可以为配置类（Table的子类），
	 *      也可为子查询（Query），on参数为多表关联的表达式，如 a.id=b.id。
	 *  </p>
	 *
	 *	@param abstTable 配置类（Table的子类）或者子查询（Query）
	 *  @param on 关联表达式
	 *  @return 当前Query对象
	 */
	public Query innerJoin(AbstTable abstTable, BoolExpr on)
	{
		from.append(Const.INNER_JOIN).append(abstTable.getString()).append(Const.ON).append(on.getString());
		return this;
	}
	
	/**
	 *	拼接outer join … on子句.
	 *
	 *  <p>
	 *      该方法方法拼接sql查询语句中的outer join … on子句，abstTable参数可以为配置类（Table的子类），
	 *      也可为子查询（Query），on参数为多表关联的表达式，如 a.id=b.id。
	 *  </p>
	 *
	 *	@param abstTable 配置类（Table的子类）或者子查询（Query）
	 *  @param on 关联表达式
	 *  @return 当前Query对象
	 */
	public Query outerJoin(AbstTable abstTable, BoolExpr on)
	{
		from.append(Const.OUTER_JOIN).append(abstTable.getString()).append(Const.ON).append(on.getString());
		return this;
	}
	
	/**
	 *	拼接join … on子句.
	 *
	 *  <p>
	 *      该方法方法拼接sql查询语句中的join … on子句，abstTable参数可以为配置类（Table的子类），
	 *      也可为子查询（Query），on参数为多表关联的表达式，如 a.id=b.id。
	 *  </p>
	 *
	 *	@param abstTable 配置类（Table的子类）或者子查询（Query）
	 *  @param on 关联表达式
	 *  @return 当前Query对象
	 */
	public Query join(AbstTable abstTable, BoolExpr on)
	{
		from.append(Const.JOIN).append(abstTable.getString()).append(Const.ON).append(on.getString());
		return this;
	}
	
	/**
	 *	拼接cross join … on子句.
	 *
	 *  <p>
	 *      该方法方法拼接sql查询语句中的cross join … on子句，abstTable参数可以为配置类（Table的子类），
	 *      也可为子查询（Query），on参数为多表关联的表达式，如 a.id=b.id。
	 *  </p>
	 *
	 *	@param abstTable 配置类（Table的子类）或者子查询（Query）
	 *  @param on 关联表达式
	 *  @return 当前Query对象
	 */
	public Query crossJoin(AbstTable abstTable, BoolExpr on)
	{
		from.append(Const.CROSS_JOIN).append(abstTable.getString()).append(Const.ON).append(on.getString());
		return this;
	}
	
	/**
	 *	拼接select子句.
	 * 
	 *  <p>
	 *      该方法拼接sql查询中的select子句，columns参数为配置类的属性数组，即表的字段数组。该方法直接把字段名拼接在
	 *      select关键字之后，用逗号隔开。方法可在sql语句提交之前多次调用，顺序不限。
	 *  </p>
	 *  
	 *	@param columns 字段数组
	 *  @return 当前Query对象
	 */
	public Query select(Column...columns)
	{
		if(columns==null || columns.length==0) return this;
		for(Column column : columns)
		{
			if(column==null) continue;
			
			if(select==null) select = new StringBuffer("select ").append(column.getAliasWithNameWithAlias());
			else select.append(",").append(column.getAliasWithNameWithAlias());
		}
		return this;
	}
	
	/**
	 *	拼接select子句.
	 *
	 *  <p>
	 *      该方法拼接sql查询中的select子句，exprs参数为函数表达式数组。该方法直接把表达式拼接在
	 *      select关键字之后，用逗号隔开。方法可在sql语句提交之前多次调用，顺序不限。
	 *  </p>
	 *  
	 *	@param exprs 函数表达式
	 *  @return 当前Query对象
	 */
	public Query select(FunExpr...exprs)
	{
		if(exprs==null || exprs.length==0) return this;
		for(FunExpr fe : exprs)
		{
			if(fe==null) continue;
			if(select==null) select = new StringBuffer("select ").append(fe.getString());
			else select.append(",").append(fe.getString());
		}
		return this;
	}
	
	/**
	 *	拼接where子句.
	 *  
	 *  <p>
	 *      该方法拼接sql查询中的where子句，expr参数为布尔表达式对象。该方法把布尔表达式拼接在
	 *      where关键字之后。方法可在sql语句提交之前多次调用，顺序不限。多次调用的where方法，
	 *      布尔表达式用sql关键字“AND”分隔。如果需要“OR”连接，可使用布尔表达式对象本身的连接功能，
	 *      具体参照{@link BoolExpr}。
	 *  </p>
	 *  
	 *	@param expr 布尔表达式
	 *  @return 当前Query对象
	 */
	public Query where(BoolExpr expr)
	{
		appendWhere();
		this.expr = expr;
		return this;
	}
	
	private void appendWhere()
	{
		if(expr==null || expr.getString()==null) return;
		if(expr.getCount()>1)
		{
			if(where==null) where = new StringBuffer(" where (").append(expr.getString()).append(")");
			else where.append(" and (").append(expr.getString()).append(")");
		}
		else
		{
			if(where==null) where = new StringBuffer(" where ").append(expr.getString());
			else where.append(" and ").append(expr.getString());
		}
		expr = null;
	}
	
	/**
	 *	拼接group by子句.
	 *
	 *  <p>
	 *      该方法拼接sql查询中的group by子句，columns参数为配置类的属性数组。该方法把属性名（字段名）
	 *      拼接在group by关键字之后。方法可在sql语句提交之前多次调用，顺序不限。多次调用group方法，
	 *      将把多个字段名连接到group by关键字之后，并用逗号分隔。
	 *  </p>
	 *  
	 *	@param columns 字段数组
	 *  @return 当前Query对象
	 */
	public Query group(Column...columns)
	{
		if(columns==null) return this;
		for(Column g : columns)
		{
			if(g==null) continue;
			if(group==null) group = new StringBuffer(" group by ").append(g.getAliasWithName());
			else group.append(",").append(g.getAliasWithName());
		}
		return this;
	}
	
	/**
	 *	拼接having子句.
	 *
	 *  <p>
	 *      该方法拼接sql查询中的having子句，exprs参数为布尔表达式数组。该方法把布尔表达式数组
	 *      拼接在having关键字之后，用逗号分隔。方法可在sql语句提交之前多次调用，顺序不限。
	 *  </p>
	 *  
	 *	@param exprs 布尔表达式
	 *  @return 当前Query对象
	 */
	public Query having(BoolExpr...exprs)
	{
		if(exprs==null) return this;
		for(BoolExpr hh : exprs)
		{
			if(hh==null) continue;
			if(having==null) having = new StringBuffer(" having ").append(hh.getString());
			else having.append(",").append(hh.getString());
		}
		return this;
	}
	
	/**
	 *	拼接order by子句.
	 *
	 *  <p>
	 *      该方法拼接sql查询中的order by子句，columns参数为配置类属性数组。该方法把属性数组（字段名）
	 *      拼接在order by关键字之后，用逗号分隔。方法可在sql语句提交之前多次调用，顺序不限，调用顺序即为
	 *      order by子句中字段的先后顺序，将影响查询结果排序。
	 *  </p>
	 *  
	 *	@param columns 字段数组
	 *  @return 当前Query对象
	 */
	public Query order(Column...columns)
	{
		if(columns==null) return this;
		for(Column o : columns)
		{
			if(o==null) continue;
			if(order==null) order = new StringBuffer(" order by ").append(o.getString());
			else order.append(",").append(o.getString());
		}
		return this;
	}
	
	/**
	 *	拼接order by子句.
	 *
	 *  <p>
	 *      该方法拼接sql查询中的order by子句，exprs参数为函数表达式。该方法把函数表达式
	 *      拼接在order by关键字之后，用逗号分隔。方法可在sql语句提交之前多次调用，顺序不限，调用顺序即为
	 *      order by子句中表达式的先后顺序，将影响查询结果排序。
	 *  </p>
	 *  
	 *	@param exprs 函数表达式数组
	 *  @return 当前Query对象
	 */
	public Query order(FunExpr...exprs)
	{
		if(exprs==null) return this;
		for(FunExpr f : exprs)
		{
			if(f==null) continue;
			if(order==null) order = new StringBuffer(" order by ").append(f.getString());
			else order.append(",").append(f.getString());
		}
		return this;
	}
	
	/**
	 *	拼接limit子句.
	 *
	 *  <p>
	 *      该方法拼接sql查询中的limit子句，offset参数为偏移量，count参数为返回结果最大行数。
	 *      方法最多仅可在sql语句提交之前调用一次。
	 *  </p>
	 *  
	 *	@param offset 偏移量
	 *  @param count 返回结果数
	 *  @return 当前Query对象
	 */
	public Query limit(Integer offset, Integer count)
	{
		limit = new StringBuffer(" limit ").append(offset).append(",").append(count);
		return this;
	}
	
	/**
	 *	拼接limit子句.
	 *
	 *  <p>
	 *      该方法拼接sql查询中的limit子句，count参数为返回结果最大行数。
	 *      方法最多仅可在sql语句提交之前调用一次。
	 *  </p>
	 *  
	 *  @param count 返回结果数
	 *  @return 当前Query对象
	 */
	public Query limit(Integer count)
	{
		limit = new StringBuffer(" limit ").append(count);
		return this;
	}
	
	/**
	 *	如果上一个where子句中包含空值，则忽略上一个where子句.
	 *
	 *  <p>
	 *      该方法检查上一个where的布尔表达式子句，如果判断值为空，则删除这个表达式。
	 *      比如a.name=''，调用此方法后，该表达式将被删除。该方法通常用于来自用户界面的
	 *      查询，这种查询通常当不设置条件时，则忽略这个查询条件。这种忽略，需要显式调用
	 *      此方法来实现。例如：
	 *  </p>
	 *  <pre>
	 *      query.where(a.name.eq(value)).nullIgnore();
	 *  </pre>
	 *  
	 *  @return 当前Query对象
	 */
	public Query nullIgnore()
	{
		if(expr!=null && expr.isNull()) expr = null;
		return this;
	}
	
	/**
	 *	如果参数指定的表达式包含空值，则忽略参数中的表达式.
	 *
	 *  <p>
	 *      该方法检查当前expr布尔表达式，如果判断值为空，则忽略这个表达式，返回null。
	 *      比如a.name=''，调用此方法后，将返回null。该方法通常用于来自用户界面的
	 *      查询，这种查询通常当不设置条件时，则忽略这个查询条件。这种忽略，需要显式调用
	 *      此方法来实现。因为本方法不返回Query对象，因此调用需要按照如下方式：
	 *  </p>
	 *  <pre>
	 *      query.where(query.nullIgnore(a.name.eq(value)));
	 *  </pre>
	 *  <p>
	 *      特别的，如果要忽略的表达式包含在or子句中，也需要用到该方法，如：
	 *  <pre>
	 *      query.where(a.id.eq(2020).or(query.nullIgnore(a.name.eq(value))));
	 *  </pre>
	 *  
	 *  @param expr 表达式
	 *  @return 参数中的BoolExpr对象或者null
	 */
	public BoolExpr nullIgnore(BoolExpr expr)
	{
		if(expr==null) return null;
		else if(expr.isNull()) return null;
		else return expr;
	}
	
	// -----------------------------------------------------------------------------------------------------------------
	
	/**
	 *	获得当前sql语句.
	 *
	 *  <p>
	 *      sql语句由select、from、where、group by、having、order by和limit子句拼接而成。
	 *      除了from子句外，其它子句均可省略，如果省略了select子句，则系统会自动加上当前表全部字段的列表
	 *      作为select子句。
	 *  </p>
	 *
	 *  @return sql语句 
	 */
 	public String getSql()
	{
		if(select==null)
		{
			String st = getSelect(table);
			select = new StringBuffer("select ").append(st);
		}
		appendWhere();
		return new StringBuffer().append(select).append(from==null?"":from).append(where==null?"":where).append(group==null?"":group).append(having==null?"":having).append(order==null?"":order).append(limit==null?"":limit).toString();
	}
	
	String getCountSql()
	{
		appendWhere();
		return new StringBuffer("select count(1) as c").append(from==null?"":from).append(where==null?"":where).append(group==null?"":group).append(having==null?"":having).append(order==null?"":order).toString();
	}
	
	static String getSelect(Table table)
	{
		List<Column> columns = table.columns;
		StringBuffer select = null;
		for(int i=0; i<columns.size(); i++)
		{
			Column c = columns.get(i);
			if(select==null) select = new StringBuffer(c.getAliasWithNameWithAlias());
			else select.append(",").append(c.getAliasWithNameWithAlias());
		}
		return select==null?null:select.toString();
	}
	
	/**
	 *	获得字符串.
	 *
	 *  @return 返回sql语句 
	 */
	public String toString()
    {
    	return getSql();
    }

	// ----------------------------------------------------------------------------------
	
	/**
	 *	取出以List表示的数据结果集.
	 *
	 *  <p>
	 *      调用该方法，即通过JdbcTemplate提交sql到数据库，并获得结果集。List的一个元素代表结果集的一行记录。
	 *      List的元素类型，为配置类中指定的pojo对象类型。如果结果集为空，则返回长度为0的List对象。
	 *  </p>
	 *
	 *	@param <R> 数据结果列表的元素类型
	 *  @return 数据结果列表
	 */
	public <R> List<R> getList()
	{
		return getList(table.pojo);
	}
	
	/**
	 *	取出以List表示的数据结果集.
	 *
	 *  <p>
	 *      调用该方法，即通过JdbcTemplate提交sql到数据库，并获得结果集。List的一个元素代表结果集的一行记录。
	 *      rowClass参数指定了List的元素类型，可以和配置类中指定的pojo对象类型不同，通常为Row类型。
	 *      如果结果集为空，则返回长度为0的List对象。
	 *  </p>
	 *
	 *	@param <R> 数据结果列表的元素类型
	 *  @param rowClass List的元素类型
	 *  @return 数据结果列表，如果结果集为空，则返回长度为0的List对象。
	 */
	public <R> List<R> getList(Class<R> rowClass)
	{
		String sql = getSql();
		logger.info(sql);
		
//		if(rowClass==Map.class)
//		{
//			List<R> list = (List<R>)this.getJdbcTemplate().queryForList(sql);
//			return list==null?new ArrayList<>():list;
//		}
		//else
		if(rowClass==Row.class)
		{
			List<Map<String, Object>> list = (List<Map<String, Object>>)this.getJdbcTemplate().queryForList(sql);
			if(list==null) return new ArrayList<>();
			for(int i=0; i<list.size(); i++) 
			{
				Row rm = new Row(list.get(i));
				list.set(i, rm);
			}
			return (List<R>)list;
		}
		else
		{
			RowMapper<R> rm = BeanPropertyRowMapper.newInstance(rowClass);
			List<R> list = this.getJdbcTemplate().query(sql, rm);
			return list==null?new ArrayList<>():list;
		}
	}
	
	/**
	 *	取出忽略分页后的结果行数，用于分页查询.
	 *
	 *  <p>
	 *      该方法会忽略limit子句，并且把select子句换成“select count(1) as c”，查询后返回一个整数。
	 *  </p>
	 *
	 *  @return 结果行数
	 */
	public Integer getCount()
	{
		String sql = getCountSql();
		logger.info(sql);
		List<Integer> values = this.getJdbcTemplate().queryForList(sql, Integer.class);
		Integer count = null;
		if(values!=null && values.size()>0) count = values.get(0);
		return count==null?0:count;
	}
	
	/**
	 *	取出一个值.
	 *
	 *  <p>
	 *      该方法通过查询获得一个简单值，通常为Integer、Long、String等类型，用于查询结果只有一行一列
	 *      的情形。valueClass参数指明返回值的类型。
	 *  </p>
	 *
	 *	@param <V> 数据值的类型
	 *  @param valueClass 数据值的class
	 *  @return 数据值，如果结果为空，则返回null。
	 */
	public <V> V getValue(Class<V> valueClass)
	{
		List<V> values = getValues(valueClass);
		if(values!=null && values.size()>0) return values.get(0);
		else return null;
	}
	
	/**
	 *	取出一列值.
	 *
	 *  <p>
	 *      该方法通过查询获得简单值的列表，通常为List&lt;Integer&gt;、List&lt;Long&gt;、List&lt;String&gt;等类型，用于查询结果只有一列
	 *      的情形。valueClass参数指明返回值List的元素类型。
	 *  </p>
	 *
	 *	@param <V> 数据值列表的元素类型
	 *  @param valueClass 数据值的class
	 *  @return 数据值列表，如果结果集为空，则返回长度为0的List对象。
	 */
	public <V> List<V> getValues(Class<V> valueClass)
	{
		String sql = getSql();
		logger.info(sql);
		List<V> values = this.getJdbcTemplate().queryForList(sql, valueClass);
		return values==null?new ArrayList<>():values;
	}
	
	/**
	 *	取出以set形式表示的结果集，可用于去重.
	 *
	 *  <p>
	 *      该方法通过查询获得简单值的集合，通常为Set&lt;Integer&gt;、Set&lt;Long&gt;、Set&lt;String&gt;等类型，用于查询结果只有一列
	 *      的情形。valueClass参数指明返回值Set的元素类型。
	 *  </p>
	 *  
	 *	@param <V> 数据值列表的元素类型
	 *  @param valueClass 数据值的class
	 *  @return 数据值的set集合，如果结果集为空，则返回长度为0的Set对象。
	 */
	public <V> Set<V> getSet(Class<V> valueClass)
	{
		List<V> list = getValues(valueClass);
		return new HashSet<V>(list);
	}
	
	/**
	 *	取出一条记录.
	 *
	 *  <p>
	 *      调用该方法，即通过JdbcTemplate提交sql到数据库，并获得数据结果。返回类型为配置类中指定的pojo对象类型。
	 *      如果结果集为空，则返回null。
	 *  </p>
	 *  
	 *  @param <R> 数据对象的元素类型
	 *  @return 数据对象，如果结果集为空，则返回null。
	 */
	public <R> R getOne()
	{
		return (R)getOne(table.pojo);
	}

	/**
	 *	取出一条记录.
	 *
	 *  <p>
	 *      调用该方法，即通过JdbcTemplate提交sql到数据库，并获得数据结果。
	 *      rowClass参数指定了返回结果类型，可以和配置类中指定的pojo对象类型不同，通常为Row类型。
	 *      如果结果集为空，则返回null。
	 *  </p>
	 *  
	 *	@param <R> 数据对象的元素类型
	 *  @param rowClass 返回结果类型
	 *  @return 数据对象，如果结果集为空，则返回null。
	 */
	public <R> R getOne(Class<R> rowClass)
	{
		StringBuffer old = this.limit;
		this.limit(1);
		List<R> list = getList(rowClass);
		this.limit = old;
		if(list!=null && list.size()>0) return list.get(0);
		else return null;
	}
	
	/**
	 *	取出以map形式表示的结果集，需要指定key，即pojo的property.
	 *  
	 *  <p>
	 *  有时，我们希望数据结果用键值对的方式呈现，比如一个key对应一条记录，key由程序开发者来指定，比如
	 *  如下形式的结果：
	 *  <pre>
	 *  {
	 *      key1 : object1,
	 *      key2 : object2,
	 *      ...
	 *      keyn : objectn
	 *  }
	 *  </pre>
	 *  <p>
	 *  其中key1、key2...keyn，为object对象property属性的实际值，object1、object2...objectn为数据对象。这种情况，
	 *  即可使用本方法，本方法通过反射机制，获取得到实际的key值。
	 *  
	 *  @param <K> 数据对象中作为key的属性类型
	 * 	@param <R> 数据对象类型
	 *	@param property 数据对象中的属性名
	 *  @return Map表示的结果集
	 */
	public <K,R> Map<K,R> getMap(String property)
	{
		return getMap(table.pojo, property);
	}
	
	/**
	 *	取出以map形式表示的结果集，需要指定key，即pojo的property.
	 *
	 *  <p>
	 *  有时，我们希望数据结果用键值对的方式呈现，比如一个key对应一条记录，key由程序开发者来指定，比如
	 *  如下形式的结果：
	 *  <pre>
	 *  {
	 *      key1 : object1,
	 *      key2 : object2,
	 *      ...
	 *      keyn : objectn
	 *  }
	 *  </pre>
	 *  <p>
	 *  其中key1、key2...keyn，为object对象property属性的实际值，object1、object2...objectn为数据对象。这种情况，
	 *  即可使用本方法，本方法通过反射机制，获取得到实际的key值。
	 *  
	 *  @param <K> 数据对象中作为key的属性类型
	 * 	@param <R> 数据对象类型
	 *  @param rowClass 对象数据类型
	 *	@param property 数据对象中的属性名
	 *  @return Map表示的结果集
	 */
	public <K,R> Map<K,R> getMap(Class<R> rowClass, String property)
	{
		List<R> list = getList(rowClass);
		return Query.toMap(list, property);
	}
	
	/**
	 *	取出以map形式表示的结果集，通过回调获得属性值作为key.
	 *
	 *  <p>
	 *  有时，我们希望数据结果用键值对的方式呈现，比如一个key对应一条记录，key由程序开发者来指定，比如
	 *  如下形式的结果：
	 *  <pre>
	 *  {
	 *      key1 : object1,
	 *      key2 : object2,
	 *      ...
	 *      keyn : objectn
	 *  }
	 *  </pre>
	 *  <p>
	 *  其中key1、key2...keyn，为keyCallback参数的getKey方法的返回值，object1、object2...objectn为数据对象。
	 *  这种情况，即可使用本方法，本方法通过调用getKey方法得到实际的key值。
	 *  
	 *  @param <K> 数据对象中作为key的属性类型
	 * 	@param <R> 数据对象类型
	 *  @param keyCallback 用来获得key值的回调接口
	 *  @return Map表示的结果集
	 */
	public <K,R> Map<K,R> getMap(KeyCallback<K,R> keyCallback)
	{
		return getMap(table.pojo, keyCallback);
	}
	
	/**
	 *	取出以map形式表示的结果集，通过回调获得属性值作为key.
	 *
	 *  <p>
	 *  有时，我们希望数据结果用键值对的方式呈现，比如一个key对应一条记录，key由程序开发者来指定，比如
	 *  如下形式的结果：
	 *  <pre>
	 *  {
	 *      key1 : object1,
	 *      key2 : object2,
	 *      ...
	 *      keyn : objectn
	 *  }
	 *  </pre>
	 *  <p>
	 *  其中key1、key2...keyn，为keyCallback参数的getKey方法的返回值，object1、object2...objectn为数据对象。
	 *  这种情况，即可使用本方法，本方法通过调用getKey方法得到实际的key值。
	 *  
	 *  @param <K> 数据对象中作为key的属性类型
	 * 	@param <R> 数据对象类型
	 *  @param rowClass 数据对象类型
	 *  @param keyCallback 用来获得key值的回调接口
	 *  @return Map表示的结果集
	 */
	public <K,R> Map<K,R> getMap(Class<R> rowClass, KeyCallback<K,R> keyCallback)
	{
		List<R> list = getList(rowClass);
		return Query.toMap(list, keyCallback);
	}
	
	/**
	 *	取出以map形式表示的结果集，通过回调获得属性值作为key和value.
	 *
	 *  <p>
	 *  有时，我们希望数据结果用键值对的方式呈现，比如一个key对应一条数据，key由程序开发者来指定，value也由
	 *  开发者指定，比如 如下形式的结果：
	 *  <pre>
	 *  {
	 *      key1 : value1,
	 *      key2 : value2,
	 *      ...
	 *      keyn : valuen
	 *  }
	 *  </pre>
	 *  <p>
	 *  其中key1、key2...keyn，为keyValueCallback参数的getKey方法的返回值，value1、value2...valuen为keyValueCallback
	 *  参数的getValue方法的返回值。这种情况，即可使用本方法，本方法通过调用getKey和getValue方法得到实际的key值和value值。
	 *  
	 *  @param <K> 数据对象中作为key的属性类型
	 *  @param <V> 数据对象类型
	 * 	@param <R> 原始数据对象类型
	 *  @param keyValueCallback 用来获得key和value值的回调接口
	 *  @return Map表示的结果集
	 */
	public <K,V,R> Map<K,V> getMap(KeyValueCallback<K,V,R> keyValueCallback)
	{
		return getMap(table.pojo, keyValueCallback);
	}
	
	/**
	 *	取出以map形式表示的结果集，通过回调获得属性值作为key和value.
	 *
	 *  <p>
	 *  有时，我们希望数据结果用键值对的方式呈现，比如一个key对应一条数据，key由程序开发者来指定，value也由
	 *  开发者指定，比如 如下形式的结果：
	 *  <pre>
	 *  {
	 *      key1 : value1,
	 *      key2 : value2,
	 *      ...
	 *      keyn : valuen
	 *  }
	 *  </pre>
	 *  <p>
	 *  其中key1、key2...keyn，为keyValueCallback参数的getKey方法的返回值，value1、value2...valuen为keyValueCallback
	 *  参数的getValue方法的返回值。这种情况，即可使用本方法，本方法通过调用getKey和getValue方法得到实际的key值和value值。
	 *  
	 *  @param <K> 数据对象中作为key的属性类型
	 *  @param <V> 数据对象类型
	 * 	@param <R> 原始数据对象类型
	 *  @param rowClass 原始数据对象类型
	 *  @param keyValueCallback 用来获得key和value值的回调接口
	 *  @return Map表示的结果集
	 */
	public <K,V,R> Map<K,V> getMap(Class<R> rowClass, KeyValueCallback<K,V,R> keyValueCallback)
	{
		List<R> list = getList(rowClass);
		return Query.toMap(list, keyValueCallback);
	}
	
	// --静态快捷方法-----------------------------------------------------------------------------------------------------
	
	/**
	 *	从table指定的表中根据主键id取出一条记录.
	 *
	 *	@param <R> 数据对象类型
	 *	@param table 配置类
	 *	@param id 主键值
	 *  @return 数据对象
	 */
	public static <R> R get(Table table, Serializable id)
	{
		List<R> list = getList(table, table.primaryKey, id, true);
		if(list!=null && list.size()>0) return list.get(0);
		else return null;
	}
	
	/**
	 *	从table指定的表中根据字段名和值取出一条记录.
	 *
	 *	@param <R> 数据对象类型
	 *  @param table 配置类
	 *	@param name 字段
	 **	@param value 字段值
	 *  @return 数据对象
	 */
	public static <R> R get(Table table, Column name, Serializable value)
	{
		List<R> list = getList(table, name, value, true);
		if(list!=null && list.size()>0) return list.get(0);
		else return null;
	}
	
	/**
	 *	从table指定的表中根据字段名和值取出所有匹配记录.
	 *
	 *	@param <R> 数据对象类型
	 *  @param table 配置类
	 *	@param name 字段
	 *	@param value 字段值
	 *  @return 数据对象列表
	 */
	public static <R> List<R> getList(Table table, Column name, Serializable value)
	{
		List<R> list = getList(table, name, value, false);
		return list==null?new ArrayList<>():list;
	}
	
	private static <R> List<R> getList(Table table, Column name, Serializable value, boolean oneOnly)
	{
		try
		{
			if(value==null) throw new Exception("The value is null!");
			String strValue = null;
			if(name instanceof Num) strValue = value.toString();
			else if(name instanceof Chr) strValue = "'"+value+"'";
			else if(name instanceof Datetime) strValue = "'"+Mysql4jUtil.formatDate((Date)value)+"'";
			
			String select = getSelect(table);
			
			StringBuffer sql = new StringBuffer("select ").append(select).append(" from ").append(table.getName()).append(" where ").append(name.name).append("=").append(strValue).append(oneOnly?" limit 1":"");
			logger.info(sql.toString());
			
			Class<R> rowClass = table.pojo;
			if(rowClass==Map.class)
			{
				return (List<R>)table.getJdbcTemplate().queryForList(sql.toString());
			}
			else if(rowClass==Row.class)
			{
				List<Map<String, Object>> list = (List<Map<String, Object>>)table.getJdbcTemplate().queryForList(sql.toString());
				if(list==null) return new ArrayList<>();
				for(int i=0; i<list.size(); i++) 
				{
					Row rm = new Row(list.get(i));
					list.set(i, rm);
				}
				return (List<R>)list;
			}
			else
			{
				RowMapper<R> rm = BeanPropertyRowMapper.newInstance(rowClass);
				return table.getJdbcTemplate().query(sql.toString(), rm);
			}
		}
		catch(Exception e)
		{
			logger.error(e);
			return null;
		}
	}
	
	// --静态转化方法-----------------------------------------------------------------------------------------------------
	
	/**
	 *	把列表转换成以map形式表示的结果集，需要指定key，即pojo的property.
	 *
	 *  @param <K> 数据对象中作为key的属性类型
	 * 	@param <R> 数据对象类型
	 * 	@param list 数据对象列表
	 *	@param property 数据对象中的属性名
	 *  @return Map表示的结果集
	 *  @see Query#getMap(String)
	 */
	public static <K,R> Map<K,R> toMap(List<R> list, String property)
	{
		Map<K,R> map = new HashMap();
		if(list==null || list.size()==0) return map;
		
		Class cls = list.get(0).getClass();
		boolean isMap = false;
		Method method = null;
		if(Map.class.isAssignableFrom(cls))
		{
			isMap = true;
		}
		else
		{
			try
			{
				String m = "get"+Mysql4jUtil.initialUpperCase(property);
				method = cls.getMethod(m, new Class[0]);
			} 
			catch(Exception e)
			{
				System.out.println(e);
				return map;
			}
		}
		if(isMap)
		{
			for(R r : list)
			{
				try
				{
					Object key = ((Map)r).get(property);
					map.put((K)key, r);
				}
				catch(Exception e)
				{
					System.out.println(e);
				}
			}
		}
		else
		{
			Object[] params = new Object[0];
			for(R r : list)
			{
				try
				{
					Object key = method.invoke(r, params);
					map.put((K)key, r);
				}
				catch(Exception e)
				{
					System.out.println(e);
				}
			}
		}
		return map;
	}
	
	/**
	 *	把列表转换成以map形式表示的结果集，通过回调获得属性值作为key.
	 *
	 *  @param <K> 数据对象中作为key的属性类型
	 * 	@param <R> 数据对象类型
	 *  @param list 数据对象列表
	 *  @param keyCallback 用来获得key值的回调接口
	 *  @return Map表示的结果集
	 *  @see Query#getMap(KeyCallback)
	 */
	public static <K,R> Map<K,R> toMap(List<R> list, KeyCallback<K,R> keyCallback)
	{
		Map<K,R> rows = new HashMap();
		if(list==null || list.size()==0) return rows;
		
		for(R row : list)
		{
			try
			{
				K key = keyCallback.getKey(row);
				rows.put(key, row);
			}
			catch(Exception e)
			{
				System.out.println(e);
			}
		}
		return rows;
	}
	
	/**
	 *	把列表转换成以map形式表示的结果集，通过回调获得属性值作为key和value.
	 *
	 *  @param <K> 数据对象中作为key的属性类型
	 *  @param <V> 数据对象类型
	 * 	@param <R> 原始数据对象类型
	 *  @param list 原始数据对象列表
	 *  @param keyValueCallback 用来获得key和value值的回调接口
	 *  @return Map表示的结果集
	 *  @see Query#getMap(KeyValueCallback)
	 */
	public static <K,V,R> Map<K,V> toMap(List<R> list, KeyValueCallback<K,V,R> keyValueCallback)
	{
		Map<K,V> rows = new HashMap();
		if(list==null || list.size()==0) return rows;
		
		for(R row : list)
		{
			try
			{
				K key = keyValueCallback.getKey(row);
				V value = keyValueCallback.getValue(row);
				rows.put(key, value);
			}
			catch(Exception e)
			{
				System.out.println(e);
			}
		}
		return rows;
	}
}
